package com.wl.common.system.service.impl;

import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.wl.common.core.constant.ConstantSystem;
import com.wl.common.core.web.dto.DataStoreDTO;
import com.wl.common.mybatis.utils.PageUtils;
import com.wl.common.system.dao.SysRoleMapper;
import com.wl.common.system.dao.SysUserMapper;
import com.wl.common.system.dao.SysUserRoleMapper;
import com.wl.common.system.domain.SysUserRole;
import com.wl.common.system.service.SysUserRoleService;
import com.wl.common.system.support.dto.SysUserDTO;
import com.wl.common.system.support.dto.UserProfileDTO;
import com.wl.common.system.support.dto.UserRoleDTO;
import com.wl.common.system.support.dto.query.SysUserQueryDTO;
import com.wl.common.system.support.vo.SysUserVO;
import com.wl.system.api.domain.SysRole;
import com.wl.system.api.domain.SysUser;
import com.wl.system.api.model.LoginUser;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author: wanglin
 * @date: 2023-09-13 周三
 * @Version: 1.0
 * @Description:
 */
@Service
public class SysUserServiceImpl implements SysUserService {
    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private SysUserRoleMapper userRoleMapper;

    @Autowired
    private SysUserRoleService userRoleService;


    @Transactional(readOnly = true)
    @Override
    public DataStoreDTO<SysUserVO> page(Pageable pageable, SysUserQueryDTO queryDto) {
        QueryWrapper<SysUser> queryWrapper = this.buildQuery(queryDto);
        Page<SysUser> page = PageUtils.transferPage(pageable);
        Page<SysUser> result = this.userMapper.selectPage(page, queryWrapper);
        return new DataStoreDTO(result.getTotal(), this.transferVo(result.getRecords()));
    }

    @Transactional(readOnly = true)
    @Override
    public DataStoreDTO<SysUserVO> dataPage(Pageable pageable, SysUserQueryDTO queryDto) {
        IPage<SysUserVO> result = this.userMapper.selectDataPage(PageUtils.transferPage(pageable), queryDto);
        return new DataStoreDTO(result.getTotal(), result.getRecords());
    }

    @Transactional(readOnly = true)
    @Override
    public List<SysUserVO> list(Sort sort, SysUserQueryDTO queryDto) {
        QueryWrapper<SysUser> queryWrapper = this.buildQuery(queryDto);
        PageUtils.transferSort(queryWrapper, sort);
        return this.transferVo(this.userMapper.selectList(queryWrapper));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(SysUserDTO dto) {
        dto.setId(null);
        userMapper.insert(this.transferEntity(null, dto));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(SysUserDTO dto) {
        Assert.hasText(dto.getId(), "id不能为空");
        SysUser entity = userMapper.selectById(dto.getId());
        Assert.notNull(entity, "找不到id为 " + dto.getId() + " 的记录");
        entity.setUserId(dto.getUserId());
        entity.setName(dto.getName());
        userMapper.updateById(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Set<String> ids) {
        if (CollectionUtils.isNotEmpty(ids)) {
            //删除用户拥有的相关的角色
            userRoleService.deleteByUserIds(ids);
            //删除用户信息
            userMapper.deleteBatchIds(ids);
        }
    }

    @Transactional(readOnly = true)
    @Override
    public SysUserVO get(String id) {
        Assert.hasText(id, "id不能为空");
        SysUserVO vo = userMapper.selectUserAndRoleById(id);
        Assert.notNull(vo, "找不到id为 " + id + " 的记录");
        return vo;
    }

    @Transactional(readOnly = true)
    @Override
    public SysUser getUserInfo(String userId) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(StringUtils.isNotBlank(userId), SysUser::getUserId, userId);
        SysUser user = userMapper.selectOne(queryWrapper);
        return user;
    }

    @Transactional(readOnly = true)
    @Override
    public LoginUser getLoginUserInfo(String userId) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(StringUtils.isNotBlank(userId), SysUser::getUserId, userId);
        SysUser user = userMapper.selectOne(queryWrapper);
        if (ObjUtil.isNull(user)) {
            return null;
        }
        LoginUser loginUser = new LoginUser();
        loginUser.setSysUser(user);
        loginUser.setUsername(user.getUserId());
        return loginUser;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void assignRolesById(UserRoleDTO dto) {
        //存在性验证
        SysUser userEntity = userMapper.selectById(dto.getUserId());
        Assert.notNull(userEntity, "用户不存在");

        //方式一：支持分配多个角色
        //获取用户已经具有的角色id
//        List<String> userRoleIdList = userRoleService.getRoleIdsByUserId(userId);

        //获取除了用户拥有的角色以外的所有角色id
//        List<String> allRoleIdList = roleService.getAllRoles().stream()
//                .filter(e -> NumberUtils.INTEGER_ZERO.equals(e.getStatus()) && !userRoleIdList.contains(e.getId()))
//                .map(e -> e.getId()).collect(Collectors.toList());

        //验证添加的角色是存在的
//        String[] split = roles.split(Constants.COMMA);
//        Assert.isTrue(split.length > NumberUtils.INTEGER_ZERO, "角色类型格式错误");
//        List<String> addRoleIdList = Lists.newArrayList();
//        for (String roleId : split) {
//            //判断分配的角色是用户未拥有的
//            Assert.isTrue(allRoleIdList.contains(roleId), "该用户已拥有: " + roleId + " 角色");
//            addRoleIdList.add(roleId);
//            userRoleMapper.insert(new UserRole(userId, roleId));
//        }
//        String roleIds = addRoleIdList.stream().collect(Collectors.joining(Constants.COMMA));

        //用户表中的角色也要更新
//        if (StringUtils.isBlank(userEntity.getRoleType())) {
//            userEntity.setRoleType(roleIds);
//        } else {
//            userEntity.setRoleType(userEntity.getRoleType() + Constants.COMMA + roleIds);
//        }
//        userMapper.updateById(userEntity);

        //方式二：分配单个角色
        //存在性验证角色id
//        SysRole roleEntity = roleMapper.selectById(roles);
        List<SysRole> roleList = roleMapper.selectBatchIds(dto.getRoleIds());
        Assert.notEmpty(roleList, "角色id不存在");
        Assert.isTrue(roleList.size() == dto.getRoleIds().size(), "角色id存在错误");

        //用户角色表中要更新
//        QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda().eq(SysUserRole::getUserId, userId);
//        List<SysUserRole> userRoleList = userRoleMapper.selectList(queryWrapper);
//        //验证该用户是否分配角色
//        Assert.notEmpty(userRoleList, "该用户没有角色类型，请联系管理员！！！");
//        userRoleList.stream().forEach(e -> {
//            e.setRoleId(roles);
//            userRoleMapper.updateById(e);
//        });

//        userRoleMapper.insertBatchList(dto.getRoleIds().stream().map(e -> new SysUserRole(dto.getUserId(), e)).collect(Collectors.toList()));
        userRoleMapper.insertBatch(dto.getRoleIds().stream().map(e -> new SysUserRole(dto.getUserId(), e)).collect(Collectors.toList()));
//        userMapper.updateById(userEntity);
    }

    @Transactional(readOnly = true)
    @Override
    public DataStoreDTO<SysUserVO> selectAllocatedList(Pageable pageable, SysUserQueryDTO queryDto) {
        IPage<SysUserVO> pageResult = userMapper.selectAllocatedList(PageUtils.transferPage(pageable), queryDto);
        return new DataStoreDTO(pageResult.getTotal(), pageResult.getRecords());
    }

    @Transactional(readOnly = true)
    @Override
    public DataStoreDTO<SysUserVO> selectUnallocatedList(Pageable pageable, SysUserQueryDTO queryDto) {
        IPage<SysUserVO> pageResult = userMapper.selectUnallocatedList(PageUtils.transferPage(pageable), queryDto);
        return new DataStoreDTO(pageResult.getTotal(), pageResult.getRecords());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelAuthUsers(String roleId, List<String> userIds) {
        if (StringUtils.isBlank(roleId) || CollectionUtils.isEmpty(userIds)) {
            return;
        }
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId).in(SysUserRole::getUserId, userIds));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void accreditBatchUser(String roleId, List<String> userIds) {
        cn.hutool.core.lang.Assert.notEmpty(userIds, "用户id不能为空");
        List<SysUser> userList = userMapper.selectBatchIds(userIds);
        cn.hutool.core.lang.Assert.notEmpty(userList, "用户id不存在");
        List<SysUserRole> entityList = Lists.newArrayList();
        userList.stream().forEach(e -> {
            cn.hutool.core.lang.Assert.isTrue(userIds.contains(e.getId()), "用户id: " + e.getId() + "不存在");
            entityList.add(new SysUserRole(e.getId(), roleId));
        });
        userRoleMapper.insertBatch(entityList);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserProfile(UserProfileDTO dto) {
        Assert.hasText(dto.getId(), "id不能为空");
        SysUser entity = userMapper.selectById(dto.getId());
        Assert.notNull(entity, "找不到id为: " + dto.getId() + " 的记录");
        entity.setName(dto.getName());
        userMapper.updateById(entity);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addUser(SysUserDTO dto) {
        cn.hutool.core.lang.Assert.notBlank(dto.getPassword(), "密码不能为空");
        //1- 参数验证
        Assert.isTrue(dto.getPassword().matches(ConstantSystem.PASSWORD_REG), "密码至少包含：数字,字母,字符中的两种以上，长度6-16");
        List<SysUser> userList = validateRepeat(dto.getUserId(), dto.getName());
        if (!userList.isEmpty()) {
            //2- 唯一性验证 账号,name
            userList.stream().forEach(e -> {
                Assert.isTrue(dto.getUserId().equals(e.getUserId()), "账号:" + dto.getUserId() + "已存在");
                Assert.isTrue(dto.getName().equals(e.getName()), "姓名: " + dto.getName() + "已存在");
            });
        }

        //验证角色id
        Assert.notEmpty(dto.getRoleIds(), "用户角色不能为空");
        List<SysRole> roleList = roleMapper.selectBatchIds(dto.getRoleIds());
        Assert.notEmpty(roleList, "用户角色不存在");
        Assert.isTrue(dto.getRoleIds().size() == roleList.size(), "用户角色存在错误");

        //新增用户
        SysUser entity = new SysUser();
        //默认密码已加密
        entity.setPassword(dto.getPassword());
        entity.setName(dto.getName());
        entity.setDescription(dto.getDescription());
        entity.setUserId(dto.getUserId());
        if (ObjUtil.isNull(dto.getStatus()) || NumberUtils.INTEGER_ZERO.equals(dto.getStatus())) {
            entity.setStatus(0);
        } else {
            entity.setStatus(1);
        }
        entity.setIsFirstLogin(true);
        entity.setId(null);
        userMapper.insert(entity);

        //新增用户角色
        List<SysUserRole> userRoleList = dto.getRoleIds().stream().map(e -> new SysUserRole(entity.getId(), e)).collect(Collectors.toList());
        userRoleMapper.insertBatch(userRoleList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUser(SysUserDTO dto) {
        Assert.hasText(dto.getId(), "id不能为空");
        SysUser entity = userMapper.selectById(dto.getId());
        Assert.notNull(entity, "找不到id为 " + dto.getId() + " 的记录");

        //1- 参数验证
        List<SysUser> userList = validateRepeat(dto.getUserId(), dto.getName());
        if (!userList.isEmpty()) {
            //2- 唯一性验证 账号,name
            userList.stream().forEach(e -> {
                if (e.getUserId().equals(dto.getUserId())) {
                    Assert.isTrue(dto.getId().equals(e.getId()), "账号:" + dto.getUserId() + "已存在");
                }
                if (e.getName().equals(dto.getName())) {
                    Assert.isTrue(dto.getId().equals(e.getId()), "姓名: " + dto.getName() + "已存在");
                }
            });
        }
        //验证角色id
        Assert.notEmpty(dto.getRoleIds(), "用户角色不能为空");
        List<SysRole> roleList = roleMapper.selectBatchIds(dto.getRoleIds());
        Assert.notEmpty(roleList, "用户角色不存在");
        Assert.isTrue(dto.getRoleIds().size() == roleList.size(), "用户角色存在错误");

        //修改用户
        entity.setName(dto.getName());
        entity.setUserId(dto.getUserId());
        if (ObjUtil.isNull(dto.getStatus()) || NumberUtils.INTEGER_ZERO.equals(dto.getStatus())) {
            entity.setStatus(0);
        } else {
            entity.setStatus(1);
        }
        entity.setDescription(dto.getDescription());
        userMapper.updateById(entity);

        //修改用户角色，删除之前所有的，在新增
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, dto.getId()));
        List<SysUserRole> userRoleList = dto.getRoleIds().stream().map(e -> new SysUserRole(dto.getId(), e)).collect(Collectors.toList());
        userRoleMapper.insertBatch(userRoleList);
    }


    private List<SysUser> validateRepeat(String userId, String name) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(StringUtils.isNotBlank(userId), SysUser::getUserId, userId)
                .or().eq(StringUtils.isNotBlank(name), SysUser::getName, name);
        return userMapper.selectList(queryWrapper);
    }

    private QueryWrapper<SysUser> buildQuery(SysUserQueryDTO queryDto) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        if (Objects.nonNull(queryDto)) {
            queryWrapper.lambda().like(StringUtils.isNotBlank(queryDto.getName()), SysUser::getName, queryDto.getName())
                    .eq(StringUtils.isNotBlank(queryDto.getUserId()), SysUser::getUserId, queryDto.getUserId())
                    .eq(Objects.nonNull(queryDto.getStatus()), SysUser::getStatus, queryDto.getStatus())
                    .ge(StringUtils.isNotBlank(queryDto.getStartCreateTime()), SysUser::getCreateTime, queryDto.getStartCreateTime())
                    .le(StringUtils.isNotBlank(queryDto.getEndCreateTime()), SysUser::getCreateTime, queryDto.getEndCreateTime());
        }
        return queryWrapper;
    }

    private SysUser transferEntity(SysUser entity, SysUserDTO dto) {
        if (Objects.isNull(entity)) {
            entity = new SysUser();
        }
        BeanUtils.copyProperties(dto, entity);
//        entity.setRoleType(RoleTypeEnum.COMMON.getKey());
        return entity;
    }

    private List<SysUserVO> transferVo(List<SysUser> entities) {
        if (CollectionUtils.isEmpty(entities)) {
            return Lists.newArrayList();
        }

        List<SysUserVO> voList = entities.stream().map(entity -> {
            SysUserVO vo = new SysUserVO();
            BeanUtils.copyProperties(entity, vo);
//            vo.setRoleTypeName(RoleTypeEnum.getValueByKey(entity.getRoleType()));
            return vo;
        }).collect(Collectors.toList());
        return voList;
    }

    private SysUserVO transferVo(SysUser entity) {
        if (Objects.isNull(entity)) {
            return null;
        }
        SysUserVO vo = new SysUserVO();
        BeanUtils.copyProperties(entity, vo);
        return vo;
    }
}

